package com.xqboss.apps.service.aliyun;

import cn.hutool.core.io.IoUtil;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.xqboss.apps.dto.aliyun.OssStsDto;
import com.xqboss.apps.enums.sys.FileTypeEnum;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;


/**
 * 阿里云oss服务
 *
 * @author Administrator
 */
@Slf4j
@Service
public class OssService {

    @Value("${aliyun.sts.endpoint}")
    private String stsEndpoint;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
    @Value("${aliyun.oss.regionId}")
    private String regionId;
    @Value("${aliyun.oss.bucket}")
    private String bucket;
    @Value("${aliyun.sts.roleArn}")
    private String roleArn;
    @Value("${aliyun.oss.host}")
    private String host;
    @Value("${aliyun.oss.cdnHost}")
    private String cdnHost;

    public OssStsDto getStsInfo(Boolean isApps) {
        String policy;
        if (isApps) {
            policy = "{\n" + "    \"Version\": \"1\", \n" + "    \"Statement\": [\n" + "        {\n" + "            \"Action\": [\n" + "                \"oss:PutObject\"\n" + "            ], \n" + "            \"Resource\": [\n" + "                \"acs:oss:*:*:" + bucket + "/user/" + SecurityUtils.getUserId() + "/" + "*\" \n" + "            ], \n" + "            \"Effect\": \"Allow\"\n" + "        }\n" + "    ]\n" + "}";
        } else {
            policy = "{\n" + "    \"Version\": \"1\", \n" + "    \"Statement\": [\n" + "        {\n" + "            \"Action\": [\n" + "                \"oss:PutObject\"\n" + "            ], \n" + "            \"Resource\": [\n" + "                \"acs:oss:*:*:" + bucket + "/img/" + "*\", \n" + "                \"acs:oss:*:*:" + bucket + "/common/" + "*\" \n" + "            ], \n" + "            \"Effect\": \"Allow\"\n" + "        }\n" + "    ]\n" + "}";
        }
        // 设置临时访问凭证的有效时间为3600秒。
        Long durationSeconds = 3600L;
//        String regionId = "";
        //构建一个阿里云客户端，用于发起请求。
        //构建阿里云客户端时需要设置AccessKey ID和AccessKey Secret。
        DefaultProfile.addEndpoint("", "Sts", stsEndpoint);
        DefaultProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);

        //构造请求，设置参数。关于参数含义和设置方法，请参见API参考。
        AssumeRoleRequest req = new AssumeRoleRequest();
        req.setSysMethod(MethodType.POST);
        req.setRoleArn(roleArn);
        req.setRoleSessionName("xq-user-" + SecurityUtils.getUserId());
        // 针对该临时权限可以根据该属性赋予规则，格式为json，没有特殊要求，默认为空
        req.setPolicy(policy);
        req.setDurationSeconds(durationSeconds);

        //发起请求，并得到响应。
        try {
            AssumeRoleResponse response = client.getAcsResponse(req);
            AssumeRoleResponse.Credentials credentials = response.getCredentials();

            OssStsDto ossInfo = new OssStsDto();
            ossInfo.setBucket(bucket);
            ossInfo.setEndpoint(endpoint);
            ossInfo.setRegionId(regionId);
            ossInfo.setExpiration(credentials.getExpiration());
            ossInfo.setAccessKeyId(credentials.getAccessKeyId());
            ossInfo.setAccessKeySecret(credentials.getAccessKeySecret());
            ossInfo.setSecurityToken(credentials.getSecurityToken());
            ossInfo.setHost(host);
            ossInfo.setCdnHost(cdnHost);
//            test(endpoint, credentials.getAccessKeyId(), credentials.getAccessKeySecret(), credentials.getSecurityToken());
            return ossInfo;
        } catch (Exception e) {
            log.error("获取OSS信息失败！", e);
            throw new ServiceException("获取OSS信息失败");
        }
    }

    public void test(String endpoint, String accessKeyId, String accessKeySecret, String securityToken) {

// 创建OSSClient实例。
//        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);
//// 将本地文件exampletest.txt上传至目标存储空间examplebucket下的src目录。
//        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, "user/1/123.txt", new File("D:\\mh\\1.txt"));
//
//// ObjectMetadata metadata = new ObjectMetadata();
//// 上传文件时设置存储类型。
//// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//// 上传文件时设置读写权限ACL。
//// metadata.setObjectAcl(CannedAccessControlList.Private);
//// putObjectRequest.setMetadata(metadata);
//
//// 上传文件。
//        ossClient.putObject(putObjectRequest);
//
//// 关闭OSSClient。
//        ossClient.shutdown();
    }

    /**
     * 存储文本
     *
     * @param fileName 文件名称
     * @param content
     * @return
     */
    public String putObject(FileTypeEnum fileType, String fileName, String content) {
        return putObject(fileType.getPath() + fileName, content);
    }


    /**
     * 存储文本
     *
     * @param objectName
     * @param content
     * @return
     */
    public String putObject(String objectName, String content) {
        // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        // 创建OSSClient实例。
        // 创建ClientBuilderConfiguration实例，您可以根据实际情况修改默认参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置是否支持CNAME。CNAME用于将自定义域名绑定到目标Bucket。
        conf.setSupportCname(true);
        OSS ossClient = new OSSClientBuilder().build(host, credentialsProvider, conf);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, objectName, new ByteArrayInputStream(content.getBytes()));
        PutObjectResult result = ossClient.putObject(putObjectRequest);
        // 关闭OSSClient。
        ossClient.shutdown();
        return host + objectName;
    }

    public String getObject(FileTypeEnum fileType, String fileName) {
        return getObject(fileType.getPath() + fileName);
    }

    public String getObject(String objectName) {
        // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        // 创建OSSClient实例。
        // 创建ClientBuilderConfiguration实例，您可以根据实际情况修改默认参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置是否支持CNAME。CNAME用于将自定义域名绑定到目标Bucket。
        conf.setSupportCname(true);
        OSS ossClient = new OSSClientBuilder().build(host, credentialsProvider, conf);
        OSSObject object = ossClient.getObject(bucket, objectName);
        String result = IoUtil.readUtf8(object.getObjectContent());
        // 关闭OSSClient。
        ossClient.shutdown();
        return result;
    }

    /**
     * 文件上传
     *
     * @param os
     * @param objectName
     */
    public void fileUpload(ByteArrayOutputStream os, String objectName) {
        // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        // 创建OSSClient实例。
        // 创建ClientBuilderConfiguration实例，您可以根据实际情况修改默认参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置是否支持CNAME。CNAME用于将自定义域名绑定到目标Bucket。
        conf.setSupportCname(true);
        OSS ossClient = new OSSClientBuilder().build(host, credentialsProvider, conf);

        try {
            //具体的文件上传，获取Excel文件的数据
            InputStream in = new ByteArrayInputStream(os.toByteArray());
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, objectName, in);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
